home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Apple WWDC 1996
/
WWDC96_1996 (CD).toast
/
Technology Materials
/
MacOS 8 Resources
/
Developer Tools
/
Mac OS 8 Interfaces & Libraries
/
Interfaces
/
PInterfaces
/
DebuggerSupport.p
< prev
next >
Wrap
Text File
|
1996-05-01
|
14KB
|
297 lines
{
File: DebuggerSupport.p
Contains: Public interface to kernel services for debuggers
Version: Technology: System 8
Release: Universal Interfaces 3.0d3 on Copland DR1
Copyright: © 1984-1996 by Apple Computer, Inc. All rights reserved.
Bugs?: If you find a problem with this file, send the file and version
information (from above) and the problem description to:
Internet: apple.bugs@applelink.apple.com
AppleLink: APPLE.BUGS
}
{$IFC UNDEFINED UsingIncludes}
{$SETC UsingIncludes := 0}
{$ENDC}
{$IFC NOT UsingIncludes}
UNIT DebuggerSupport;
INTERFACE
{$ENDC}
{$IFC UNDEFINED __DEBUGGERSUPPORT__}
{$SETC __DEBUGGERSUPPORT__ := 1}
{$I+}
{$SETC DebuggerSupportIncludes := UsingIncludes}
{$SETC UsingIncludes := 1}
{$IFC UNDEFINED __TYPES__}
{$I Types.p}
{$ENDC}
{$IFC UNDEFINED __KERNEL__}
{$I Kernel.p}
{$ENDC}
{$IFC UNDEFINED __MACHINEEXCEPTIONS__}
{$I MachineExceptions.p}
{$ENDC}
{$PUSH}
{$ALIGN POWER}
{$LibExport+}
{$IFC FOR_SYSTEM8_PREEMPTIVE }
{
In addition to the normal kernel API, the kernel provides a set of services
which are specific to debuggers. These services are all accessed through the
DebuggerSupport library.
This first service is debugger registration and unregistration. For a debugger
to register itself with the kernel, it calls DSRegisterDebugger. (The kernel
allows only one registered debugger; multiple debuggers can be supported
externally by registering a dispatching entity as the debugger.) When a debugger
has successfully registered itself, it is able to receive exceptions from
debuggable tasks. Unregistering is simply the reverse of registering. The
kernel automatically unregisters a debugger when it terminates if the debugger
has not already unregistered itself. DSRegisterDebugger should be the first
call made to this library.
To receive an exception, the debugger calls DSWaitForException, passing it a
pointer to a DSExceptionRecord and a time limit. This call blocks until either
an exception arrives or the time limit expires (pass kDurationForever to wait
indefinitely). Note that this semantic essentially requires the debugger to
be multithreaded.
A DSExceptionRecord contains the ID of the excepted task, along with the IDs
of the task's team and address space, and a message ID corresponding to the
particular exception. The details of the exception are contained in the
exception record's ExceptionInformation structure, which includes pointers
to the task's registers and other exception state. The debugger may directly
modify this exception data, and, within limits, these changes will be forced
into the task's state upon resuming execution. (Changes to certain parts of
the exception data, such as the privileged and interrupt enable bits of the
exception MSR, will be ignored.)
DSResumeFromException is used to resume the excepted task's execution or to
propagate the exception on. It takes as parameters the exception ID and an
exception return status. The status may be either noErr or any nonzero error
code. noErr signifies that the debugger has cured the exception and the excepted
task should continue execution, using the state from the exception data. Any
other status value will cause the exception to be propagated to the installed
exception handler, if any. If there is no installed handler, or if that handler
fails to cure the exception, the exception is again presented to the debugger in
another message. This time, returning a nonzero return status will cause the
task to be terminated. (Double notification of exceptions allows a debugger to
catch exceptions either first, last, or at both times.)
Not all exceptions will be sent to the debugger. Exceptions in kernel tasks
or in kernel code which runs on behalf of user tasks is not debuggable through
normal means. Furthermore, exceptions occurring in privileged tasks with
hardware interrupts disabled, or during execution at secondary interrupt level,
or while running message system Accept functions, fall into the same category
as kernel exceptions and are not sent to the debugger.
The debugger may call DSHoldTasks to request the kernel to hold a task or set
of tasks, making them ineligible for execution. The tasks are specified with a
task ID and scope (task only, task and children, task family, or task team). If
any task to be held is already blocked inside the kernel, e.g. due to a page
fault, I/O operation, or message send, holding it will cause it to remain
ineligible even after it has unblocked. Releasing held tasks with DSReleaseTasks
allows them to become eligible again.
DSGetTaskState is used to determine a task's scheduler state (runnable or blocked),
and, if blocked, what its PC and SP values were at the point it blocked. If a
task is running a software interrupt it will have scheduler state for both its
normal execution and the execution of the software interrupt.
DSReadMemory and DSWriteMemory are used to access task memory. To read memory,
the debugger simply calls DSReadMemory. To modify memory, the debugger must first
call DSCreateMemoryAccess to obtain a memory write access right to the desired page
of memory. Using that access right, it may then call DSWriteMemory to perform the
modification. DSWriteMemory performs appropriate processor cache synchronization and
backing storage coordination to support modifying code memory, e.g. for instruction
breakpoints. DSDeleteMemoryAccess is used to release an access right.
Some implementations of the kernel and hardware may support data breakpoints. To
find out what data breakpoint support (if any) is available, the debugger calls
DSGetDataBreakpointInformation. DSSetDataBreakpoint is used to set or clear a
data breakpoint. The implementation may cause excess exceptions which will have to
be filtered out by the debugger: breakpoints may occur in the wrong address space
or on an address which is outside the range specified but which lies within the
resolution range supported by the implementation.
Exception notification record
}
TYPE
DSExceptionRecordPtr = ^DSExceptionRecord;
DSExceptionRecord = RECORD
exceptedTaskID: TaskID;
exceptedKernelProcessID: KernelProcessID;
exceptedTaskAddrSpaceID: AddressSpaceID;
exceptionID: MessageID;
exception: ExceptionInformation;
END;
{ Task state record }
DSKernelStatePtr = ^DSKernelState;
DSKernelState = RECORD
kernelState: SchedulerState;
PC: LogicalAddress;
SP: LogicalAddress;
END;
DSTaskStatePtr = ^DSTaskState;
DSTaskState = RECORD
taskState: DSKernelState;
swiState: DSKernelState;
END;
{ ID to specify write access rights to a particular page in logical memory }
DSMemoryAccessID = ^LONGINT;
{ SchedulerState values }
CONST
kInactiveState = ' ';
kPageFaultState = 'PFLT';
kMessageSendState = 'MSND';
kMessageReceiveState = 'MRCV';
kHeldState = 'HELD';
kEventFlagState = 'EFLG';
kTerminatingOtherProcessState = 'OTRM';
kTerminatingCurrentProcessState = 'CTRM';
kTimerDelayState = 'DLYQ';
kKernelQueueState = 'QBLK';
kRunState = 'RUN ';
kSemaphoreReadState = 'MSRD';
kSemaphoreWriteState = 'MSWR';
kTaskStartingState = 'STRT';
kTaskTerminatingState = 'TERM';
{
Describes the data breakpoint facility provided by the current implementation.
maxBreakpoints is the maximum number of data breakpoints available (may be zero).
breakpointResolution determines the worst case range of addresses to which a data
breakpoint applies, as follows: if the nominal breakpoint address is addr, the
actual range of addresses breakpointed may, in the worst case, be
[(addr & ~(breakpointResolution - 1)) ..
(addr & ~(breakpointResolution - 1)) + breakpointResolution - 1].
}
TYPE
DSDataBreakpointInformationPtr = ^DSDataBreakpointInformation;
DSDataBreakpointInformation = RECORD
maxBreakpoints: ItemCount;
breakpointResolution: ByteCount;
END;
CONST
kDataBreakpointInformationVersion = 1;
{
The access types to which a data breakpoint should apply. Use
kDSBreakDisable to clear a data breakpoint. Note that the implementation
may not support breakpointing read and write accesses independently; in
that case specifying either option will have the same effect (break on
any access).
}
TYPE
DSDataBreakpointOptions = OptionBits;
CONST
kDSBreakDisable = $00000000;
kDSBreakOnReadAccess = $00000001;
kDSBreakOnWriteAccess = $00000002;
{
Debugger Services functions
Register the debugger. Returns kernelIDErr if there is already a debugger
registered.
}
FUNCTION DSRegisterDebugger: OSStatus; C;
{
Unregister the debugger. This is also done automatically by the kernel if
the debugger terminates.
}
FUNCTION DSUnregisterDebugger: OSStatus; C;
{ Wait specified amount of time for an exception message from the kernel. }
FUNCTION DSWaitForException(VAR exceptionRecord: DSExceptionRecord; timeLimit: Duration): OSStatus; C;
{
Resume execution of a task halted by an earlier exception. If exceptionReturnStatus
is noErr, resume the task, else propagate the exception. If the propagated exception
remains unhandled, a second exception notification will be generated.
}
FUNCTION DSResumeFromException(exceptionID: MessageID; exceptionReturnStatus: OSStatus): OSStatus; C;
{ Make the specified task(s) ineligible for execution, until released by DSReleaseTasks. }
FUNCTION DSHoldTasks(taskID: TaskID; scope: TaskRelationship): OSStatus; C;
{ Make the specified held task(s) eligible again for execution. }
FUNCTION DSReleaseTasks(taskID: TaskID; scope: TaskRelationship): OSStatus; C;
{
Get the scheduler state for a task. The task may be in a software interrupt or in
normal execution; if normal, state->swiState.kernelState will be kInactiveState. In
either case, the appropriate state->taskState.kernelState or state->swiState.kernelState
will be kRunState if the task is running, and if so the corresponding PC and SP values
are invalid and will be returned as zero. If the task is blocked in normal execution
then state->taskState.PC and state->taskState.SP will reflect the PC and SP at the time
of the system call which caused the task to block. Similarly, if the task is blocked
in a software interrupt, hence not running, then state->swiState.PC and state->swiState.SP
will be nonzero.
}
FUNCTION DSGetTaskState(taskID: TaskID; VAR state: DSTaskState): OSStatus; C;
{
Create a write access right to the page for logical address dstAddr in address
space addrSpaceID. This makes the page physically resident and prevents subsequent
reads or writes of the page from or to backing storage. The access right is returned
in memAccessID.
}
FUNCTION DSCreateMemoryAccess(addrSpaceID: AddressSpaceID; dstAddr: LogicalAddress; VAR memAccessID: DSMemoryAccessID): OSStatus; C;
{
Modify the memory to which an access right has been obtained. memAccessID is the access
right, dstAddr is the target address, srcDataPtr points to the source data to be written,
and numBytes is the size of the write. The range [dstAddr..dstAddr + numBytes - 1] must lie
entirely within the page specified by the access right. If the destination memory is code,
processor caches will be synchronized appropriately.
}
FUNCTION DSWriteMemory(memAccessID: DSMemoryAccessID; dstAddr: LogicalAddress; srcDataPtr: UNIV Ptr; numBytes: ByteCount): OSStatus; C;
{
Delete an access right and allow normal backing storage activity for that page. memAccessID
is the access right. Note: changes to the page up to this point will NOT be written to
backing storage.
}
FUNCTION DSDeleteMemoryAccess(memAccessID: DSMemoryAccessID): OSStatus; C;
{
Read memory. srcAddr is the address to read from, addrSpaceID specifies the address space,
dstDataPtr points to the debugger buffer into which to copy the data, and numBytes is the
size of the read.
}
FUNCTION DSReadMemory(addrSpaceID: AddressSpaceID; srcAddr: LogicalAddress; dstDataPtr: UNIV Ptr; numBytes: ByteCount): OSStatus; C;
{
Set a data breakpoint. addrSpaceID specifies the address space, which may or may not be
used. breakAddr is the logical address to break on. numBytes is a hint as to the range
of addresses to break on. The address range [breakAddr .. (breakAddr + numBytes -1)] must
lie within the worst case data breakpoint resolution which the implmentation supports, as
determined via DSGetDataBreakpointInformation. A data breakpoint hit will result in a
memory access exception of type kDataBreakpointException. The implementation may cause
excess exceptions which will have to be filtered out by the debugger, e.g. breakpoints
may occur in the wrong address space or on an address which is outside the range specified
but which lies within the resolution range supported by the implementation. To "fix up"
a memory reference which triggered a data breakpoint exception without removing the
data breakpoint, use DSReadMemory or DSWriteMemory. Data breakpoints may be disallowed
on certain addresses which are used by system code; DSSetDataBreakpoint will return
kernelInUseErr for such addresses.
}
FUNCTION DSSetDataBreakpoint(addrSpaceID: AddressSpaceID; breakAddr: LogicalAddress; numBytes: ByteCount; options: DSDataBreakpointOptions): OSStatus; C;
{
Get information about data breakpoint support. Returns the number of breakpoints available in
the current implementation and the worst case address resolution of a data breakpoint.
}
FUNCTION DSGetDataBreakpointInformation(version: PBVersion; VAR info: DSDataBreakpointInformation): OSStatus; C;
{$ENDC}
{$ALIGN RESET}
{$POP}
{$SETC UsingIncludes := DebuggerSupportIncludes}
{$ENDC} {__DEBUGGERSUPPORT__}
{$IFC NOT UsingIncludes}
END.
{$ENDC}